/**
 * This file is part of 1genia trampoline
 * Copyright (C) 2007 1genia (contact@1genia.com)
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; version 3 of the License. 
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details. 
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; see the file COPYING.TXT.  If not,
 * write to the Free Software Foundation, Inc., 51 Franklin Street,
 * Fifth Floor, Boston, MA 02110-1301, USA. 
 **/
package com.genia.toolbox.basics.bean;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;

import com.genia.toolbox.basics.process.Comparators;

/**
 * base class for {@link SortedList} and {@link WeakSortedSet}.
 * 
 * @param <V>
 *          the type of the elements of the {@link AbstractWeakSortedCollection}.
 */
@SuppressWarnings("serial")
public abstract class AbstractWeakSortedCollection<V>
    extends ArrayList<V>
{

  /**
   * the comparator to compare objects.
   */
  private transient final Comparator<? super V> localComparator;



  /**
   * constructor.
   */
  @SuppressWarnings("unchecked")
  public AbstractWeakSortedCollection()
  {
    this((Comparator<? super V>) Comparators.NATURAL_COMPARATOR);
  }



  /**
   * constructor.
   * 
   * @param comparator
   *          the comparator to compare objects
   */
  public AbstractWeakSortedCollection(Comparator<? super V> comparator)
  {
    this.localComparator = comparator;
  }



  /**
   * Inserts the specified element at the specified position in this list.
   * Shifts the element currently at that position (if any) and any subsequent
   * elements to the right (adds one to their indices).
   * 
   * @param index
   *          index at which the specified element is to be inserted.
   * @param element
   *          element to be inserted.
   * @see java.util.ArrayList#add(int, java.lang.Object)
   */
  @Override
  public void add(int index, V element)
  {
    checkElementForIndex(index, element, false);
    super.add(index, element);
  }



  /**
   * Appends the specified element to the end of this list.
   * 
   * @param object
   *          element to be appended to this list.
   * @return <tt>true</tt> (as per the general contract of Collection.add).
   * @see java.util.ArrayList#add(java.lang.Object)
   */
  @Override
  public abstract boolean add(V object);



  /**
   * Appends all of the elements in the specified Collection to the end of this
   * list, in the order that they are returned by the specified Collection's
   * Iterator. The behavior of this operation is undefined if the specified
   * Collection is modified while the operation is in progress. (This implies
   * that the behavior of this call is undefined if the specified Collection is
   * this list, and this list is nonempty.)
   * 
   * @param collection
   *          the elements to be inserted into this list.
   * @return <tt>true</tt> if this list changed as a result of the call.
   * @see java.util.ArrayList#addAll(java.util.Collection)
   */
  @Override
  public boolean addAll(Collection<? extends V> collection)
  {
    boolean res = false;
    for (V element : collection) {
      res = true;
      add(element);
    }
    return res;
  }



  /**
   * Inserts all of the elements in the specified Collection into this list,
   * starting at the specified position. Shifts the element currently at that
   * position (if any) and any subsequent elements to the right (increases their
   * indices). The new elements will appear in the list in the order that they
   * are returned by the specified Collection's iterator.
   * 
   * @param index
   *          index at which to insert first element from the specified
   *          collection.
   * @param collection
   *          elements to be inserted into this list.
   * @return <tt>true</tt> if this list changed as a result of the call.
   * @see java.util.ArrayList#addAll(int, java.util.Collection)
   */
  @Override
  public boolean addAll(int index, Collection<? extends V> collection)
  {
    throw new UnsupportedOperationException();
  }



  /**
   * Replaces the element at the specified position in this list with the
   * specified element.
   * 
   * @param index
   *          index of element to replace.
   * @param element
   *          element to be stored at the specified position.
   * @return the element previously at the specified position.
   * @see java.util.ArrayList#set(int, java.lang.Object)
   */
  @Override
  public V set(int index, V element)
  {
    checkElementForIndex(index, element, true);
    V oldElement = get(index);
    super.set(index, element);
    return oldElement;
  }



  /**
   * check that the element given in parameter can be put in the given index in
   * the {@link Collection}.
   * 
   * @param index
   *          the index to put the element at
   * @param element
   *          the element to put in the {@link Collection}
   * @param isReplace
   *          <code>true</code> if the new element will replace the current
   *          one, <code>false</code> if the new element is inserted and the
   *          current one is shifted
   * @throws IllegalArgumentException
   *           if the element cannot be put in the given index
   */
  private void checkElementForIndex(int index, V element, boolean isReplace)
      throws IllegalArgumentException
  {
    if ((index > 0 && comparator().compare(get(index - 1), element) > 0) || (index < size() - (isReplace ? 1 : 0) && comparator().compare(element, get(index + (isReplace ? 1 : 0))) > 0)) {
      throw new IllegalArgumentException("The element won't be ordered");
    }
  }



  /**
   * getter for the comparator property.
   * 
   * @return the comparator
   */
  public Comparator<? super V> comparator()
  {
    return localComparator;
  }
}
